package org.xqh.study.google.guava.concurrent;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Monitor;

import java.util.List;

/*
public abstract static class Guard：一个标识线程是否等待的布尔条件，Guard类总是与单一的Monitor相关联，Monitor可以在任意时间从任意占用Monitor的线程检查Guard，这样代码的编写将不在关心Guard是否被检查的频率。
public abstract boolean isSatisfied()：Guard内部提供的抽象方法，isSatisfied()，当被关联的Monitor被占用时，Guard的此方法会被调用，该方法的实现必须取决于被关联Monitor保护的状态，并且状态不可修改。
Monitor方法的使用场景中一般都要使用try/finnally 区域，以确保能够释放锁。
Monitor有几个常用的方法：
1、enter()：进入到当前Monitor，无限期阻塞，等待锁。(这里没有Guard)
2、enter(long time, TimeUnit unit)：进入到当前Monitor，最多阻塞给定的时间，返回是否进入Monitor。
3、tryEnter()：如果可以的话立即进入Monitor，不阻塞，返回是否进入Monitor。
4、enterWhen(Guard guard)：进入当前Monitor，等待Guard的isSatisfied()为true后，继续往下执行 ，但可能会被打断; 为false，会阻塞。
5、enterIf(Guard guard)：如果Guard的isSatisfied()为true，进入当前Monitor。等待获得锁(这里会等待获取锁)，不需要等待Guard satisfied。
6、tryEnterIf(Guard guard)：如果Guard的isSatisfied()为true并且可以的话立即进入Monitor，不等待获取锁(这里不等待获取锁)，也不等待Guard satisfied。
 */
public class MonitorExample {
    private static final int MAX_SIZE = 10;
    private Monitor monitor = new Monitor();
    public List<String> list = Lists.newArrayList();

    //标识线程是否等待的布尔条件
    Monitor.Guard listBelowCapacity = new Monitor.Guard(monitor) {
            @Override
            public boolean isSatisfied() {
                return list.size() < MAX_SIZE;
            }
    };

    public void addToListWait(String item) throws InterruptedException {
        // 超过MAX_SIZE， 会锁死（阻塞）
        this.monitor.enterWhen(listBelowCapacity);
        try {
            list.add(item);
            System.out.println("添加元素[" + item + "]成功，当前List.size=" + list.size() + "～");
        } finally { // 确保线程会退出Monitor锁
            monitor.leave();
        }
    }

    public void addToListSkipWait(String item) throws InterruptedException {
        // 超过MAX_SIZE， 会锁死
        //this.monitor.enterWhen(listBelowCapacity);

        // 超过返回false  不会锁死
        Boolean isOK = monitor.tryEnterIf(listBelowCapacity);
        System.out.println("Thread[" + Thread.currentThread().getName() + "] item=" + item + ",获取执行权：isOK=" + isOK);
        if (isOK) {
            try {
                list.add(item);
                System.out.println("添加元素[" + item + "]成功，当前List.size=" + list.size() + "～");
            } finally { // 确保线程会退出Monitor锁
                monitor.leave();
            }
        }
    }

}
